package socketTest.chapter03;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * 名称: ToUpperTCPNIOServer.java <br>
 * 描述: <br>
 * 最近修改时间:2018/5/3 17:08 <br>
 *
 * @version [版本号, V1.0]
 * @since 2018/5/3 17:08
 * @author zhipingzhang  
 */
public class ToUpperTCPNIOServer2 {

    //服务器IP
    public static final String SERVER_IP = "127.0.0.1";

    //服务器端口号
    public static final int SERVER_PORT = 10005;

    //最多处理1024个字符
    public static final int MAX_BYTES = 1024;
    //请求终结字符串


    /***
     * 启动服务器
     * @param serverIp 服务器监听的端口号，服务器ip无需指定，系统自动分配
     * @param serverPort 服务器监听的端口号，服务器ip无需指定，系统自动分配
     */
    public void startServer(String serverIp, int serverPort) throws IOException {

        //使用NIO需要用到ServerSocketChannel
        //其中包含一个ServerSocket对象
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //创建服务器地址对象
        InetSocketAddress inetSocketAddress = new InetSocketAddress(serverIp, serverPort);

        //服务器绑定地址
        serverSocketChannel.bind(inetSocketAddress);
        //设置为非阻塞
        serverSocketChannel.configureBlocking(false);

        //注册到selector，会调用ServerSocket的accept
        //我们用selector监听accept能否返回
        //当调用accept可以返回时，会得到通知
        //注意，是可以返回，还需要调用accept
        Selector selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
            //调用select，阻塞在这里，直到有注册的channel满足条件
            System.out.println("服务启动，等待连接。。。");
            int select = selector.select();

            if (select > 0) {

                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    iterator.remove();
                    try {
                        if (key.isAcceptable()) {
                            ServerSocketChannel channel = (ServerSocketChannel) key.channel();
                            SocketChannel socketChannel = channel.accept();
                            System.out.println("接收到连接请求:"
                                    + socketChannel.getRemoteAddress().toString());
                            socketChannel.configureBlocking(false);
                            socketChannel.register(selector, SelectionKey.OP_READ);

                        } else if (key.isReadable()) {
                            // read
                            receiveMessage(key);
                            key.cancel();
                            key.channel().close();
                        }
                    } catch (IOException e) {
                        //当客户端Socket关闭时，会走到这里，清理资源
                        System.out.println("捕获到异常，连接关闭");
                        key.cancel();
                        try {
                            key.channel().close();
                        } catch (IOException e1) {
                            e1.printStackTrace();
                        }
                    }

                }

            }
        }
    }


    private void receiveMessage(SelectionKey key) throws IOException {
        SocketChannel socketChannel = (SocketChannel) key.channel();
        ByteBuffer byteBuffer = ByteBuffer.allocate(4);
        StringBuilder stringBuilder = new StringBuilder();

        while (socketChannel.read(byteBuffer) > 0) {
            byteBuffer.flip();
            //读取为String
            String recv = new String(byteBuffer.array());
            System.out.println("接收到：" + recv);
            stringBuilder.append(recv.toUpperCase());
            byteBuffer.clear();
        }
        socketChannel.write(ByteBuffer.wrap(stringBuilder.toString().getBytes()));

    }

    public static void main(String[] args) throws Exception {
        ToUpperTCPNIOServer2 server = new ToUpperTCPNIOServer2();
        server.startServer(SERVER_IP, SERVER_PORT);
    }
}